package ru.spbau.goncharova.chat.protocol;

import ru.spbau.goncharova.chat.client.Client;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class ProtocolHeader {

    private final int length;
    private final int version;
    private final ProtocolFlags flags;
    private final MessageType messageType;

    public static final ByteOrder order = ByteOrder.BIG_ENDIAN;

    /**
     * Returns header's size in bytes.
     * @return header's size in bytes
     */
    public static int getSize() {
        return 16;
    }

    private ProtocolHeader(int length, int version, ProtocolFlags flags, MessageType messageType) {
        this.length = length;
        this.version = version;
        this.flags = flags;
        this.messageType = messageType;
    }

    public ProtocolHeader(ProtocolFlags flags, MessageType messageType, byte[] data) {
        this.version = Client.VERSION;
        this.flags = flags;
        this.messageType = messageType;
        this.length = data.length;// + getSize();
    }

    /**
     * Extracts header from the byte buffer. The buffer is supposed to be big-endian.
     * @param buffer buffer to extract header from
     * @return the header
     */
    public static ProtocolHeader extractHeader(ByteBuffer buffer) {
        if (buffer.order() != order) {
            throw new IllegalArgumentException("Big-endian convention should be used in ru.spbau.goncharova.chat.protocol.");
        }
        int version = buffer.getInt();
        int messageTypeId = buffer.getInt();
        MessageType messageType = MessageType.values()[messageTypeId - 1];
        int flagsEncoded = buffer.getInt();
        ProtocolFlags flags = new ProtocolFlags(flagsEncoded);
        int length = buffer.getInt();
        return new ProtocolHeader(length, version, flags, messageType);
    }

    /**
     * Puts the header into byte buffer. The buffer is supposed to be big-endian.
     * @param buffer buffer to put header to
     * @return input buffer with header encoded
     */
    public ByteBuffer encode(ByteBuffer buffer) {
        if (buffer.order() != order) {
            throw new IllegalArgumentException("Big-endian convention should be used in ru.spbau.goncharova.chat.protocol.");
        }
        buffer.putInt(version);
        buffer.putInt(messageType.getCode());
        buffer.putInt(flags.encode());
        buffer.putInt(length);
        return buffer;
    }

    public int getLength() {
        return length;
    }

    public int getVersion() {
        return version;
    }

    public MessageType getMessageType() {
        return messageType;
    }

    public ProtocolFlags getFlags() {
        return flags;
    }

    @Override
    public String toString() {
        return "Version = " + version + "\nMessageType = " + messageType + "\nFlags = " + flags + "\nLength = " + length;
    }

}
